package com.hex.ds.hdrs.engine.exec;

import com.hex.ds.hdrs.agent.service.AgentManager;
import com.hex.ds.hdrs.agent.service.AgentSession;
import com.hex.ds.hdrs.app.service.AppManager;
import com.hex.ds.hdrs.center.service.CenterManager;
import com.hex.ds.hdrs.common.constant.Const;
import com.hex.ds.hdrs.common.constant.ErrorCode;
import com.hex.ds.hdrs.common.exception.BizException;
import com.hex.ds.hdrs.common.utils.HdrsDateUtil;
import com.hex.ds.hdrs.engine.manager.RunningManager;
import com.hex.ds.hdrs.engine.manager.ToRunManager;
import com.hex.ds.hdrs.engine.service.DispatcherService;
import com.hex.ds.hdrs.period.job.po.JobTask;
import com.hex.ds.hdrs.period.task.po.PeriodTask;
import com.hex.ds.hdrs.period.task.service.TaskService;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;


@Slf4j
public class DispatcherExec extends Thread {

    private volatile boolean stop = false;
    private volatile boolean run = true;
    private volatile boolean runningFlag = false;

    private ToRunManager toRunManager;
    private RunningManager runningManager;
    private CenterManager centerManager;
    private AppManager appManager;
    private AgentManager agentManager;
    private TaskService taskService;

    private String groupCode;
    private String threadName;

    //避免同个任务日志循环打印
    private List<String> taslLogList = new ArrayList<>();

    public String getGroupCode() {
        return groupCode;
    }

    public String getThreadName() {
        return threadName;
    }

    public boolean getRun() {
        return run;
    }

    public boolean getStop() {
        return stop;
    }

    public DispatcherExec(DispatcherService dispatcherService, String threadName, String groupCode) {
        this.toRunManager = dispatcherService.getToRunManager();
        this.runningManager = dispatcherService.getRunningManager();
        this.centerManager = dispatcherService.getCenterManager();
        this.appManager = dispatcherService.getAppManager();
        this.agentManager = dispatcherService.getAgentManager();
        this.taskService = dispatcherService.getTaskService();
        this.groupCode = groupCode;
        this.threadName = threadName;
    }

    /**
     * 线程正在处理任务标志
     *
     * @return
     */
    public boolean getRunningFlag() {
        return runningFlag;
    }

    /**
     * 线程暂停
     */
    public synchronized void stopThread() {
        // 如果stop已经为true，则当前线程等待
        while (stop) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
        }
        // 当stop为false时，才设置为true
        stop = true;
    }

    /**
     * 线程继续
     */
    public synchronized void continueThread() {
        if (stop) {
            stop = false;
            notifyAll();
        }
    }

    /**
     * 线程关闭
     */
    public void closeThread() {
        synchronized (this) {
            notifyAll();
        }
        run = false;
    }

    /**
     * 分发器执行
     */
    @Override
    public void run() {
        while (run) {
            try {
                if (this.isCanExec()) {
                    // 任务正在处理
                    runningFlag = true;
                    log.debug("【DispatcherExec.run】【{}】线程开始=======》", this.threadName);
                    PeriodTask task = toRunManager.dealJobTask(groupCode);
                    if (null != task) {
                        log.debug("【DispatcherExec】线程【{}应用组为{}】分发器获取到 taskCode: {},jobCode:{}", this.threadName, groupCode, task.getTaskCode(), task.getJobCode());
                        this.dispatcherExec(task);
                    } else {
                        log.debug("【DispatcherExec】线程【{}应用组为{}】分发器取任务为空", this.threadName, groupCode);
                        Thread.sleep(50);
                    }
                } else {
                    log.debug("【DispatcherExec.stop】:{},【centerManager.isCanDeal()】: {}", stop, centerManager.isCanDeal());
                    Thread.sleep(100);
                }
            } catch (Exception e) {
                log.error("【DispatcherExec.run】取任务异常:", e);
            } finally {
                log.debug("【DispatcherExec.run】取任务执行结束【{}】线程结束《=======", this.threadName);
                runningFlag = false;
                toRunManager.threadSleep();
            }
        }
        log.error("【DispatcherExec.run】线程跳出【{}】", threadName);
    }

    /**
     * 检查资源
     *
     * @param task
     */
    public void dispatcherExec(PeriodTask task) {
        String jobCode = task.getJobCode();
        String taskCode = task.getTaskCode();
        String bizDate = task.getBizDate();
        log.debug("分发器--检查资源【任务编码: {}】【业务日期: {}】【作业编码:{}】开始=======》", taskCode, bizDate, jobCode);
        if (toRunManager.isContainsJob(jobCode)) {
            log.warn("分发器--重复任务,作业编码: {},任务编码: {},业务日期: {}", jobCode, taskCode, bizDate);
            return;
        }
        JobTask jobTask = toRunManager.getJob(jobCode);
        if (jobTask == null) {
            log.warn("分发器--分发队列的toRunJobMap中已不存在该作业,作业编码: {},任务编码: {},业务日期: {}", jobCode, taskCode, bizDate);
            return;
        }
        try {
            if (Const.TASK_STOP.equals(task.getTaskStatus())) {
                log.warn("分发器--任务状态为暂停中，任务不处理，作业编码: {},任务编码: {},业务日期: {}", jobCode, taskCode, bizDate);
                throw new BizException(ErrorCode.ERROR_820012);
            }

            log.debug("【1】DB判断是否到达执行时间--开始");
            taskService.checkRunTime(task);
            log.debug("【1】DB判断是否到达执行时间--结束");

            log.debug("【2】DB校验上游依赖是否完成--开始");
            String taskLogKey = taskCode + bizDate;
            if (this.taskService.checkUpJobIsFinish(task)) {
                if (!taslLogList.contains(taskLogKey)) {
                    log.warn("【3】【任务编码: {}】【业务日期: {}】【作业编码:{}】DB校验上游依赖 有未完成……………………", taskCode, bizDate, jobCode);
                }
                taslLogList.add(taskLogKey);
                String errorMsg = taskService.getUpDependErrorMsg(task,ErrorCode.ERROR_820004.getMessage());
                throw new BizException(ErrorCode.ERROR_820004,errorMsg);
            }
            if (taslLogList.contains(taskLogKey)) {
                taslLogList.remove(taskLogKey);
            }
            log.debug("【2】DB校验上游依赖是否完成--结束");

            log.debug("【3】更新任务信息--开始 ts:{}", HdrsDateUtil.getCurTs());
            AgentSession agentSession = taskService.updateTaskInfo(task, jobTask);
            log.debug("【3】更新任务信息--结束 ts:{}", HdrsDateUtil.getCurTs());

            log.debug("【5】【任务编码: {}】【业务日期: {}】【作业编码:{}】的任务发送--开始", taskCode, bizDate, jobCode);
            agentSession.sendToAgent(task);
            log.debug("【5】【任务编码: {}】【业务日期: {}】【作业编码:{}】任务发送--结束", taskCode, bizDate, jobCode);
        } catch (BizException e) {
            runningManager.taskDealFail(task, e.getErrMsg());
            taskService.taskRollBack(e.getCode(), jobTask, task, e.getErrMsg());
        } catch (Exception e) {
            runningManager.taskDealFail(task, e.getMessage());
            taskService.taskRollBack("未知异常", jobTask, task, e.getMessage());
        } finally {
            log.debug("分发器--检查资源【任务编码: {}】【业务日期: {}】【作业编码: {}】结束《=======", taskCode, bizDate, jobCode);
        }
    }

    /**
     * 是否可执行
     *
     * @return
     */
    public boolean isCanExec() {
        if (!centerManager.isCanDeal()) {
            log.warn("【DispatcherExec.isCanExec】【警告】该中心不是Master……………………");
            return false;
        }
        if (stop) {
            log.debug("【DispatcherExec.isCanExec】分发器暂停======");
            return false;
        }
        return true;
    }

}
